﻿namespace Behemoth.SharePoint {

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;

    using Behemoth.SharePoint.Logging;

    public static class SPListEventHandlerExtensions {

        #region Working with List Events

        public static void BindEventsToList(this SPWeb web, string listName, Type listEventHandlerType, List<SPEventReceiverType> events) {
            ULSTraceLogging ulsLog = ULSTraceLogging.Default;
            if (web == null)
                return; // TODO throw null arg exception instead

            SPList targetList = null;
            try {
                targetList = web.Lists[listName];
                if (targetList == null)
                    throw new NullReferenceException();
           } catch (NullReferenceException ex) {
                string msg = string.Format("No list found with name '{0}' at web '{1}'. Check your site's configuration, or if this is a development server you may need to do an iisreset.", listName, web.Url);
                ulsLog.Write(msg, TraceSeverity.Exception);
                ulsLog.Write(ex);
                throw new Exception(msg); // , ex
            }
            targetList.BindEventsToList(listEventHandlerType, events);
        }

        public static void BindEventsToList(this SPList list, Type listEventHandlerType, List<SPEventReceiverType>events) {
            ULSTraceLogging ulsLog = ULSTraceLogging.Default;

            //Exception ex2 = null;
            string msg = string.Empty;
            ulsLog.Write(string.Format("Adding event receivers to list '{0}' at web '{1}'", list.Title, list.ParentWebUrl), TraceSeverity.InformationEvent);

            // TODO ensure assemblyName and className look similar to the following
            // "DocPoint.SharePoint.Perdue.DriverSafety, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1287b40c7eb1d233";
            // "DocPoint.SharePoint.Perdue.DriverSafety.MetadataReplicationEventHandler";
            string assemblyName = System.Reflection.Assembly.GetAssembly(listEventHandlerType).FullName;
            string className = listEventHandlerType.FullName;

            foreach (SPEventReceiverType eventType in events) {
                try {
                    list.EventReceivers.Add(eventType, assemblyName, className);
                } catch (NullReferenceException ex) {
                    msg = string.Format("Unexpected error adding event receivers to list '{0}' at web '{1}'. This list event receiver was recently deactivated. You must restart IIS before re-activating this feature. ", list.Title, list.ParentWebUrl);
                    ulsLog.Write(msg, TraceSeverity.Exception);
                    ulsLog.Write(ex);
                    // mot really sure what to do with this one, seems to indicate there 
                    // isn't any issue, because the event is already attached to the list...
                    throw new Exception(msg);
                }
            } // foreach
            // catch (Exception ex) {
            //    msg = string.Format("Unexpected error adding event receivers to list '{0}' at web '{1}'.", libName, web.Url);
            //    ulsLog.Write(msg, TraceSeverity.Exception);
            //    ulsLog.Write(ex);
            //    throw new Exception(msg, ex);
            //}
        }

        public static void UnbindEventsFromList(this SPWeb web, string listName, Type listEventHandlerType) {
            ULSTraceLogging ulsLog = ULSTraceLogging.Default;
            if (web == null)
                return; // TODO throw null arg exception instead

            SPList targetList = null;
            try {
                targetList = web.Lists[listName];
                if (targetList == null)
                    throw new NullReferenceException();
           } catch (NullReferenceException ex) {
                string msg = string.Format("No list found with name '{0}' at web '{1}'. Check your site's configuration, or if this is a development server you may need to do an iisreset.", listName, web.Url);
                ulsLog.Write(msg, TraceSeverity.Exception);
                ulsLog.Write(ex);
                throw new Exception(msg); // , ex
            }
            targetList.UnbindEventsFromList(listEventHandlerType);
        }
        public static void UnbindEventsFromList(this SPList list, Type listEventHandlerType) {
            ULSTraceLogging ulsLog = ULSTraceLogging.Default;

            // TODO ensure assemblyName and className look similar to the following
            // "DocPoint.SharePoint.Perdue.DriverSafety, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1287b40c7eb1d233";
            // "DocPoint.SharePoint.Perdue.DriverSafety.MetadataReplicationEventHandler";
            string assemblyName = Assembly.GetAssembly(listEventHandlerType).FullName;
            string className = listEventHandlerType.FullName;

            try {
                List<SPEventReceiverDefinition> events = new List<SPEventReceiverDefinition>();
                foreach (SPEventReceiverDefinition recv in list.EventReceivers) {
                    if (string.Equals(recv.Assembly, assemblyName, StringComparison.InvariantCultureIgnoreCase)
                        && string.Equals(recv.Class, className, StringComparison.InvariantCultureIgnoreCase)) {
                        events.Add(recv);
                    }
                }
                // can change an enumeration while you are in it...
                foreach (SPEventReceiverDefinition recvEvent in events) {
                    string msg = string.Format(
                        "Removing receiver Assembly='{0}', Class='{1}', Id='{2}'. The associated feature is being deactivated in list '{4}/{3}'.",
                        recvEvent.Assembly,
                        recvEvent.Class,
                        recvEvent.Id,
                        list.Title,
                        list.ParentWebUrl
                    );
                    ulsLog.Write(msg, TraceSeverity.Monitorable);
                    recvEvent.Delete();
                }
            } catch (Exception ex) {
                // If we are deactivating, and the list is gone, well, that's not really a problem is it???
                string msg = string.Format("Unexpected error deactivating event receivers in list '{0}' at web '{1}'.", list.Title, list.ParentWebUrl);
                ulsLog.Write(ex.Message, TraceSeverity.Monitorable);
                ulsLog.Write(msg, TraceSeverity.InformationEvent);
            }
        }

        #endregion

    } // class

} // namespace
